home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_include / ASM-ARM / ARCH-VNC / TIME.H < prev    next >
C/C++ Source or Header  |  1999-09-17  |  7KB  |  233 lines

  1. /*
  2.  * linux/include/asm-arm/arch-vnc/time.h
  3.  *
  4.  * Copyright (c) 1997 Corel Computer Corp.
  5.  * Slight modifications to bring in line with ebsa285 port.
  6.  *  -- Russell King.
  7.  *  Added LED driver (based on the ebsa285 code) - Alex Holden 28/12/98.
  8.  */
  9.  
  10. #include <linux/config.h>
  11. #include <linux/mc146818rtc.h>
  12.  
  13. #include <asm/leds.h>
  14. #include <asm/system.h>
  15.  
  16. #undef IRQ_TIMER
  17. #define IRQ_TIMER        IRQ_TIMER4
  18.  
  19. #define mSEC_10_from_14 ((14318180 + 100) / 200)
  20.  
  21. extern __inline__ unsigned long gettimeoffset (void)
  22. {
  23.     int count;
  24.  
  25.     static int count_p = (mSEC_10_from_14/6);    /* for the first call after boot */
  26.     static unsigned long jiffies_p = 0;
  27.  
  28.     /*
  29.      * cache volatile jiffies temporarily; we have IRQs turned off. 
  30.      */
  31.     unsigned long jiffies_t;
  32.  
  33.     /* timer count may underflow right here */
  34.     outb_p(0x00, 0x43);    /* latch the count ASAP */
  35.  
  36.     count = inb_p(0x40);    /* read the latched count */
  37.  
  38.     /*
  39.      * We do this guaranteed double memory access instead of a _p 
  40.      * postfix in the previous port access. Wheee, hackady hack
  41.      */
  42.      jiffies_t = jiffies;
  43.  
  44.     count |= inb_p(0x40) << 8;
  45.  
  46.     /* Detect timer underflows.  If we haven't had a timer tick since 
  47.        the last time we were called, and time is apparently going
  48.        backwards, the counter must have wrapped during this routine. */
  49.     if ((jiffies_t == jiffies_p) && (count > count_p))
  50.         count -= (mSEC_10_from_14/6);
  51.     else
  52.         jiffies_p = jiffies_t;
  53.  
  54.     count_p = count;
  55.  
  56.     count = (((mSEC_10_from_14/6)-1) - count) * tick;
  57.     count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
  58.  
  59.     return count;
  60. }
  61.  
  62. extern __inline__ int reset_timer (void)
  63. {
  64. #ifdef CONFIG_LEDS
  65.     static unsigned int count = 50;
  66.     static int last_pid;
  67.  
  68.     if (current->pid != last_pid) {
  69.         last_pid = current->pid;
  70.         if (last_pid)
  71.             leds_event(led_idle_end);
  72.         else
  73.             leds_event(led_idle_start);
  74.     }
  75.  
  76.     if (--count == 0) {
  77.         count = 50;
  78.         leds_event(led_timer);
  79.     }
  80. #endif
  81.     return 1;
  82. }
  83.  
  84. unsigned long set_rtc_mmss(unsigned long nowtime)
  85. {
  86.     int retval = 0;
  87.     int real_seconds, real_minutes, cmos_minutes;
  88.     unsigned char save_control, save_freq_select;
  89.  
  90.     save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
  91.     CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
  92.  
  93.     save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
  94.     CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
  95.  
  96.     cmos_minutes = CMOS_READ(RTC_MINUTES);
  97.     if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
  98.         BCD_TO_BIN(cmos_minutes);
  99.  
  100.     /*
  101.      * since we're only adjusting minutes and seconds,
  102.      * don't interfere with hour overflow. This avoids
  103.      * messing with unknown time zones but requires your
  104.      * RTC not to be off by more than 15 minutes
  105.      */
  106.     real_seconds = nowtime % 60;
  107.     real_minutes = nowtime / 60;
  108.     if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
  109.         real_minutes += 30;        /* correct for half hour time zone */
  110.     real_minutes %= 60;
  111.  
  112.     if (abs(real_minutes - cmos_minutes) < 30) {
  113.         if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
  114.             BIN_TO_BCD(real_seconds);
  115.             BIN_TO_BCD(real_minutes);
  116.         }
  117.         CMOS_WRITE(real_seconds,RTC_SECONDS);
  118.         CMOS_WRITE(real_minutes,RTC_MINUTES);
  119.     } else
  120.         retval = -1;
  121.  
  122.     /* The following flags have to be released exactly in this order,
  123.      * otherwise the DS12887 (popular MC146818A clone with integrated
  124.      * battery and quartz) will not reset the oscillator and will not
  125.      * update precisely 500 ms later. You won't find this mentioned in
  126.      * the Dallas Semiconductor data sheets, but who believes data
  127.      * sheets anyway ...                           -- Markus Kuhn
  128.      */
  129.     CMOS_WRITE(save_control, RTC_CONTROL);
  130.     CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
  131.  
  132.     return retval;
  133. }
  134.  
  135. /*
  136.  * We don't have a RTC to update!
  137.  */
  138. extern __inline__ void update_rtc(void)
  139. {
  140.     static long last_rtc_update = 0;    /* last time the cmos clock got updated */
  141.  
  142.     /* If we have an externally synchronized linux clock, then update
  143.      * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
  144.      * called as close as possible to 500 ms before the new second starts.
  145.      */
  146.     if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
  147.         xtime.tv_usec > 50000 - (tick >> 1) &&
  148.         xtime.tv_usec < 50000 + (tick >> 1)) {
  149.         if (set_rtc_mmss(xtime.tv_sec) == 0)
  150.             last_rtc_update = xtime.tv_sec;
  151.         else
  152.             last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
  153.     }
  154. }
  155.  
  156. extern __inline__ unsigned long get_cmos_time(void)
  157. {
  158.     unsigned int year, mon, day, hour, min, sec;
  159.     int i;
  160.  
  161.     // check to see if the RTC makes sense.....
  162.     if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0)
  163.         return mktime(1970, 1, 1, 0, 0, 0);
  164.  
  165.     /* The Linux interpretation of the CMOS clock register contents:
  166.      * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
  167.      * RTC registers show the second which has precisely just started.
  168.      * Let's hope other operating systems interpret the RTC the same way.
  169.      */
  170.     /* read RTC exactly on falling edge of update flag */
  171.     for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
  172.         if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
  173.             break;
  174.  
  175.     for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
  176.         if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
  177.             break;
  178.  
  179.     do { /* Isn't this overkill ? UIP above should guarantee consistency */
  180.         sec = CMOS_READ(RTC_SECONDS);
  181.         min = CMOS_READ(RTC_MINUTES);
  182.         hour = CMOS_READ(RTC_HOURS);
  183.         day = CMOS_READ(RTC_DAY_OF_MONTH);
  184.         mon = CMOS_READ(RTC_MONTH);
  185.         year = CMOS_READ(RTC_YEAR);
  186.     } while (sec != CMOS_READ(RTC_SECONDS));
  187.  
  188.     if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
  189.         BCD_TO_BIN(sec);
  190.         BCD_TO_BIN(min);
  191.         BCD_TO_BIN(hour);
  192.         BCD_TO_BIN(day);
  193.         BCD_TO_BIN(mon);
  194.         BCD_TO_BIN(year);
  195.     }
  196.     if ((year += 1900) < 1970)
  197.         year += 100;
  198.     return mktime(year, mon, day, hour, min, sec);
  199. }
  200.  
  201. /*
  202.  * Set up timer interrupt, and return the current time in seconds.
  203.  */
  204. extern __inline__ unsigned long setup_timer (void)
  205. {
  206.     unsigned int c;
  207.  
  208.     /* Turn on the RTC */
  209.     outb(13, 0x70);
  210.     if ((inb(0x71) & 0x80) == 0)
  211.         printk("RTC: *** warning: CMOS battery bad\n");
  212.  
  213.     outb(10, 0x70);        /* select control reg */
  214.     outb(32, 0x71);        /* make sure the divider is set */
  215.     outb(11, 0x70);        /* select other control reg */
  216.     c = inb(0x71) & 0xfb;    /* read it */
  217.     outb(11, 0x70);
  218.     outb(c | 2, 0x71);    /* turn on BCD counting and 24 hour clock mode */
  219.     
  220.     /* enable PIT timer */
  221.     /* set for periodic (4) and LSB/MSB write (0x30) */
  222.     outb(0x34, 0x43);
  223.     outb((mSEC_10_from_14/6) & 0xFF, 0x40);
  224.     outb((mSEC_10_from_14/6) >> 8, 0x40);
  225.  
  226.     /*
  227.      * Default the date to 1 Jan 1970 00:00:00
  228.      * You will have to run a time daemon to set the
  229.      * clock correctly at bootup
  230.      */
  231.     return get_cmos_time();
  232. }
  233.